home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / PowerPlant / LBalloonTracker / LBalloonTracker.cp next >
Encoding:
Text File  |  1996-10-24  |  18.1 KB  |  694 lines  |  [TEXT/CWIE]

  1. // ===========================================================================
  2. //    LBalloonTracker.cp                      ©1996 CS&T Inc. All rights reserved.
  3. // ===========================================================================
  4. //    
  5. //    LBalloonTracker implements Balloon Help for PowerPlant view hierarchies.
  6.  
  7. // system headers
  8. #include <Balloons.h>
  9. #include <Resources.h>
  10.  
  11. // PowerPlant headers
  12. #include <LControl.h>
  13. #include <LString.h>
  14. #include <LView.h>
  15. #include <PP_Constants.h>
  16. #include <UException.h>
  17. #include <UMemoryMgr.h>
  18. #include <UResourceMgr.h>
  19.  
  20. // project headers
  21. #include "LBalloonTracker.h"
  22.  
  23.  
  24. // ===========================================================================
  25. //    • LBalloonTracker::Init                               LBalloonTracker::Init •
  26. // ===========================================================================
  27. //    
  28. //    This class is used to initialise the LBalloonTracker class at static 
  29. //    initialisation time.  Its principal task is to determine if Balloon Help 
  30. //    is available.
  31.  
  32. #pragma mark ••• LBalloonTracker::Init •••
  33.  
  34. class LBalloonTracker::Init
  35. {
  36.     Init();
  37.     ~Init();
  38. };
  39.  
  40.  
  41. LBalloonTracker::Init::Init()
  42. {
  43.     long    result;
  44.     OSErr    err;
  45.     
  46.     err = ::Gestalt(gestaltHelpMgrAttr, &result);
  47.     LBalloonTracker::sHasBalloonHelp = ((err == noErr) && 
  48.                                         (result & (1L << gestaltHelpMgrPresent)));
  49.     
  50.     LBalloonTracker::ClearCache();
  51. }
  52.  
  53.  
  54. LBalloonTracker::Init::~Init()
  55. {
  56.     // there's nothing to do
  57. }
  58.  
  59.  
  60. // ===========================================================================
  61. //    • LBalloonTracker::Loader                         LBalloonTracker::Loader •
  62. // ===========================================================================
  63. //    
  64. //    This is a stack-based class for loading an LBalloonTracker's balloon help 
  65. //    resource ('PPbl').  The constructor (1) saves the current resource file;  
  66. //    (2) makes the tracker's resource file current;  (3) loads the resource 
  67. //    if it's not already there;  and (4) locks it.  The destructor reverses 
  68. //    these steps.
  69.  
  70. #pragma mark -
  71. #pragma mark ••• LBalloonTracker::Loader •••
  72.  
  73. class LBalloonTracker::Loader
  74. {
  75. public:
  76.             Loader(const LBalloonTracker& inTracker);
  77.             ~Loader();
  78. private:
  79.     Int16    mSavedFile;
  80.     Handle    mHandle;
  81.     SInt8    mState;
  82. };
  83.  
  84.  
  85. // ---------------------------------------------------------------------------
  86. //        • Loader
  87. // ---------------------------------------------------------------------------
  88. //    Constructor.
  89.  
  90. LBalloonTracker::Loader::Loader(const LBalloonTracker& inTracker)
  91.     : mSavedFile(::CurResFile()), mHandle(NULL), mState(0)
  92. {
  93.     // Check if the given balloon tracker has valid info in it.  At this 
  94.     // point, the current resource file has been saved into mSavedFile.
  95.     
  96.     if (inTracker.HasBalloonFile() && 
  97.         inTracker.HasBalloonDataID() && 
  98.         (inTracker.mBalloonData != NULL))
  99.     {
  100.         // We have valid info
  101.         
  102.         LBalloonTracker::BalloonDef**    balloonData    = inTracker.mBalloonData;
  103.         
  104.         mHandle = reinterpret_cast<Handle>(balloonData);
  105.         
  106.         // Set the current resource file to the one belonging to inTracker
  107.         ::UseResFile(inTracker.mBalloonFile);
  108.         
  109.         // Load the balloon help resource if it's not already in memory
  110.         
  111.         if (*mHandle == NULL)
  112.         {
  113.             ::LoadResource(mHandle);
  114.             if (::ResError() != noErr)
  115.                 mHandle = NULL;
  116.         }
  117.         
  118.         // If we managed to load the resource, save its memory state and lock it
  119.         
  120.         if (mHandle != NULL)
  121.         {
  122.             mState = ::HGetState(mHandle);
  123.             ::HLock(mHandle);
  124.         }
  125.     }
  126. }
  127.  
  128.  
  129. // ---------------------------------------------------------------------------
  130. //        • ~Loader
  131. // ---------------------------------------------------------------------------
  132. //    Destructor.  If the balloon help resource was loaded, its memory state 
  133. //    (purged, locked, etc) is restored.  The resource file that was current at 
  134. //    the time of construction is restored also.
  135.  
  136. LBalloonTracker::Loader::~Loader()
  137. {
  138.     if (mHandle != NULL)
  139.         ::HSetState(mHandle, mState);
  140.     
  141.     ::UseResFile(mSavedFile);
  142. }
  143.  
  144.  
  145. // ===========================================================================
  146. //    • LBalloonTracker                                         LBalloonTracker •
  147. // ===========================================================================
  148. #pragma mark -
  149. #pragma mark ••• LBalloonTracker •••
  150.  
  151.  
  152. // The resource type of our balloon help
  153. static const ResType    rPPBalloonData    = 'PPbl';
  154.  
  155. // The structure of our balloon help
  156.  
  157. typedef struct {
  158.     Uint16    length;
  159.     PaneIDT    paneID;
  160.     Uint16    type;
  161.     union {
  162.         Uint8            pstrs[1];
  163.         ResIDT            picts[4];
  164.         ResIDT            teres[4];
  165.         ResIDT            strs[4];
  166.         HMStringResType    stres[4];
  167.     } u;
  168. } OneBalloon;
  169.  
  170. typedef union BalloonDataOrChar {
  171.     OneBalloon    b;
  172.     char        c[1];
  173. } BalloonDataOrChar;
  174.  
  175. struct LBalloonTracker::BalloonDef {
  176.     Uint16                vers;
  177.     Uint32                options;
  178.     Uint16                procid;
  179.     Uint16                variant;
  180.     Uint16                count;
  181.     BalloonDataOrChar    elem[1];
  182. };
  183.  
  184. // static member variables
  185. Int16                    LBalloonTracker::sDefaultResFile    = ::CurResFile();
  186. Boolean                    LBalloonTracker::sHasBalloonHelp;
  187. LPane*                    LBalloonTracker::sLastBalloonPane;
  188. LBalloonTracker*        LBalloonTracker::sLastBalloonTracker;
  189. Rect                    LBalloonTracker::sLastHelpRect;
  190. Int16                    LBalloonTracker::sLastHelpIndex;
  191. Int16                    LBalloonTracker::sLastHelpOptions;
  192. Int16                    LBalloonTracker::sLastHelpProcID;
  193. Int16                    LBalloonTracker::sLastHelpVariant;
  194. Point                    LBalloonTracker::sLastHelpTip;
  195. LBalloonTracker::Init    LBalloonTracker::sInit;
  196.  
  197.  
  198. // ---------------------------------------------------------------------------
  199. //        • SetDefaultBalloonFile    [static]
  200. // ---------------------------------------------------------------------------
  201. //    Sets the resource file to be used in all subsequently created balloon 
  202. //    trackers.  By default, the balloon help resources ('PPbl') are looked for 
  203. //    in the application's resource file.  Call this function if you want to 
  204. //    look in an other file instead (eg, if your balloon help is in a separate 
  205. //    file).
  206.  
  207. void
  208. LBalloonTracker::SetDefaultBalloonFile(Int16 inBalloonResFile)
  209. {
  210.     sDefaultResFile = inBalloonResFile;
  211. }
  212.  
  213.  
  214. // ---------------------------------------------------------------------------
  215. //        • LBalloonTracker()
  216. // ---------------------------------------------------------------------------
  217. //    Default constructor.  The balloon tracker is disabled (because it doesn't 
  218. //    have a balloon help resource ID).  It can subseqently be enabled by a call 
  219. //    to SetBalloonsID().
  220.  
  221. LBalloonTracker::LBalloonTracker()
  222.     : mBalloonDataID(0), mBalloonFile(sDefaultResFile), 
  223.       mBalloonData(NULL)
  224. {
  225. }
  226.  
  227.  
  228. // ---------------------------------------------------------------------------
  229. //        • LBalloonTracker(ResIDT inBalloonsID)
  230. // ---------------------------------------------------------------------------
  231. //    Constructor.  The balloon tracker will look for a balloon help resource 
  232. //    with an ID of inBalloonsID in the default balloon help resource file.
  233.  
  234. LBalloonTracker::LBalloonTracker(ResIDT inBalloonsID)
  235.     : mBalloonDataID(0), mBalloonFile(sDefaultResFile), 
  236.       mBalloonData(NULL)
  237. {
  238.     SetBalloonDataID(inBalloonsID);
  239. }
  240.  
  241.  
  242. // ---------------------------------------------------------------------------
  243. //        • ~LBalloonTracker
  244. // ---------------------------------------------------------------------------
  245. //    Destructor.  Remove any visible balloon if it belongs to this balloon 
  246. //    tracker.
  247.  
  248. LBalloonTracker::~LBalloonTracker()
  249. {
  250.     RemoveBalloonsIfInTracker();
  251. }
  252.  
  253.  
  254. // ---------------------------------------------------------------------------
  255. //        • SetBalloonsID
  256. // ---------------------------------------------------------------------------
  257. //    Changes the resource ID of the balloon help resource in which this balloon 
  258. //    tracker will look for balloon help.
  259.  
  260. void
  261. LBalloonTracker::SetBalloonDataID(ResIDT inBalloonDataID)
  262. {
  263.     RemoveBalloonsIfInTracker();
  264.     
  265.     mBalloonDataID    = inBalloonDataID;
  266.     mBalloonData    = NULL;
  267.     
  268.     if (IsBalloonHelpAvailable() && HasBalloonFile() && HasBalloonDataID())
  269.     {
  270.         // don't load the balloon data into memory
  271.         StResLoad    dontLoadData;
  272.         Handle        rsrcHand;
  273.         Int16        savedFile;
  274.         
  275.         savedFile = ::CurResFile();
  276.         ::UseResFile(mBalloonFile);
  277.         rsrcHand = ::Get1Resource(rPPBalloonData, mBalloonDataID);
  278.         ::UseResFile(savedFile);
  279.         
  280.         // If we can't load the balloon help, it's no big deal, so we 
  281.         // simply ignore the error and assign NULL to mBalloonData.
  282.         
  283.         mBalloonData = reinterpret_cast<BalloonDef **>(rsrcHand);
  284.     }
  285. }
  286.  
  287.  
  288. // ---------------------------------------------------------------------------
  289. //        • GetBalloonID
  290. // ---------------------------------------------------------------------------
  291. //    Given an LPane and a point in port coordinates, this function returns 
  292. //    (1) the pane's ID; (2) its balloon help index; (3) its hot rect; and (4) 
  293. //    its tip location.  Derived classes can override this function to allow 
  294. //    Balloon Help text to vary within a single pane.
  295.  
  296. void
  297. LBalloonTracker::GetBalloonID(
  298.     LPane*        inHitPane, 
  299.     Point        /* inPortPt */, 
  300.     PaneIDT&    outPaneID, 
  301.     Int16&        outHelpIndex, 
  302.     Rect&        outHotRect, 
  303.     Point&        outTipPoint) const
  304. {
  305.     Assert_(inHitPane != NULL);
  306.     
  307.     LView*    superView    = inHitPane->GetSuperView();
  308.     PaneIDT    paneID;
  309.     Int16    helpIndex;
  310.     Rect    hotRect;
  311.     Point    tipPt;
  312.     
  313.     // Get pane's ID
  314.     
  315.     paneID = inHitPane->GetPaneID();
  316.     
  317.     // Get help index.  The index dictates which help message will be 
  318.     // displayed for the given pane, and depends on the pane's state. 
  319.     // For ordinary panes, the "enabled" or "disabled" message is 
  320.     // displayed, depending on the pane's enabled state.  For 
  321.     // descendents of LControl, the "enabled" message is displayed if 
  322.     // the control's value is 0, the "checked" message is displayed 
  323.     // if the control's value is 1, and the "other" message is 
  324.     // displayed for any other value.
  325.     
  326. #if __option(RTTI)
  327.     
  328.     // we have RTTI -- use pane value for LControls
  329.     
  330.     if (inHitPane->IsEnabled())
  331.     {
  332.         LControl*    theHitControl    = dynamic_cast<LControl *>(inHitPane);
  333.         
  334.         if (theHitControl != NULL)
  335.         {
  336.             Int32    paneValue    = inHitPane->GetValue();
  337.             
  338.             if (paneValue == 0)
  339.                 helpIndex = kHMEnabledItem;
  340.             else if (paneValue == 1)
  341.                 helpIndex = kHMCheckedItem;
  342.             else
  343.                 helpIndex = kHMOtherItem;
  344.         }
  345.         else
  346.             helpIndex = kHMEnabledItem;
  347.     }
  348.     else
  349.         helpIndex = kHMDisabledItem;
  350.     
  351. #else    // __option(RTTI)
  352.     
  353.     // no RTTI -- we can only rely on enabled state
  354.     helpIndex = inHitPane->IsEnabled() ? kHMEnabledItem : kHMDisabledItem;
  355.     
  356. #endif    // __option(RTTI)
  357.     
  358.     // Get pane's "hot" (i.e., frame) rect (in global coordinates).  If the 
  359.     // pane has a superview, we return the intersection of the pane's frame 
  360.     // and its superview's revealed rect.
  361.     
  362.     inHitPane->CalcPortFrameRect(hotRect);
  363.     
  364.     if (superView != NULL)
  365.     {
  366.         Rect    revealedRect;
  367.         
  368.         superView->GetRevealedRect(revealedRect);
  369.         ::SectRect(&revealedRect, &hotRect, &hotRect);
  370.     }
  371.     
  372.     inHitPane->PortToGlobalPoint(topLeft(hotRect));
  373.     inHitPane->PortToGlobalPoint(botRight(hotRect));
  374.     
  375.     // Get pane's tip location (also in global coordinates).
  376.     // We place the tip in the bottom right corner of the pane's 
  377.     // hot rectangle.  If this rectangle is small, we place the tip 
  378.     // in the center of the pane instead.
  379.     
  380.     if (hotRect.right - hotRect.left >= 16)
  381.         tipPt.h = hotRect.right - 8;
  382.     else
  383.         tipPt.h = (hotRect.right + hotRect.left) / 2;
  384.     
  385.     if (hotRect.bottom - hotRect.top >= 16)
  386.         tipPt.v = hotRect.bottom - 8;
  387.     else
  388.         tipPt.v = (hotRect.bottom + hotRect.top) / 2;
  389.         
  390.     // return all of the values we've computed
  391.     outPaneID        = paneID;
  392.     outHelpIndex    = helpIndex;
  393.     outHotRect        = hotRect;
  394.     outTipPoint        = tipPt;
  395. }
  396.  
  397.  
  398. // ---------------------------------------------------------------------------
  399. //        • TrackBalloons
  400. // ---------------------------------------------------------------------------
  401. //    This function tracks the mouse and displays the help balloons for panes 
  402. //    belonging to inHitView's pane hierarchy.  InGlobalPt and inPortPt give 
  403. //    the mouse location in global and port coordinates, respectively.
  404.  
  405. void
  406. LBalloonTracker::TrackBalloons(
  407.     LView*    inHitView, 
  408.     Point    inPortPt)
  409. {
  410.     LPane*            theHitPane    = NULL;
  411.     HMMessageRecord    helpMsg;
  412.     Int16            theHitIndex, helpOptions, helpProcID, helpVariant;
  413.     Rect            theHotRect;
  414.     Point            theTipPoint;
  415.     Boolean            foundHelp, paneChanged, indexChanged, rectChanged;
  416.     Boolean            removeIfNotFound, dataChanged;
  417.     OSErr            err;
  418.     
  419.     Assert_(inHitView != NULL);
  420.     
  421.     // do we have Balloon Help ?
  422.     if (!IsBalloonHelpAvailable())
  423.         return;
  424.     
  425.     // is Balloon Help turned on ?
  426.     if (!::HMGetBalloons())
  427.     {
  428.         // it's turned off -- clear cached variables
  429.         
  430.         if (sLastBalloonPane != NULL)
  431.             ClearCache();
  432.         
  433.         return;
  434.     }
  435.     
  436.     // do we have balloon data ?  if not, just return.
  437.     if (!HasBalloonFile() || !HasBalloonDataID())
  438.     {
  439.         return;
  440.     }
  441.     
  442.     // does the given view contain the mouse location ?
  443.     if (!inHitView->Contains(inPortPt.h, inPortPt.v))
  444.     {
  445.         // the view doesn't contain the mouse -- ignore
  446.         return;
  447.     }
  448.     
  449.     // locate the deepest Pane that contains the mouse location
  450.     theHitPane = inHitView->FindDeepSubPaneContaining(inPortPt.h, inPortPt.v);
  451.     if (theHitPane == NULL)
  452.         theHitPane = inHitView;
  453.     
  454.     removeIfNotFound = true;
  455.     
  456.     // locate the deepest Pane that has balloon data
  457.     for (foundHelp = false; 
  458.          theHitPane != NULL; 
  459.          theHitPane = theHitPane->GetSuperView())
  460.     {
  461.         PaneIDT    theHitID;
  462.         
  463.         GetBalloonID(theHitPane, inPortPt, theHitID, theHitIndex, 
  464.                      theHotRect, theTipPoint);
  465.         
  466.         // check for "special" pane IDs -- they indicate that we should ignore 
  467.         // this pane.
  468.         
  469.         if ((theHitID == PaneIDT_Undefined) || (theHitID == PaneIDT_Unspecified))
  470.         {
  471.             if (theHitID == PaneIDT_Unspecified)
  472.                 removeIfNotFound = false;
  473.             break;
  474.         }
  475.         
  476.         foundHelp = FindBalloon(theHitID, theHitIndex, helpMsg, helpOptions, 
  477.                                 helpProcID, helpVariant);
  478.         
  479.         if (foundHelp)
  480.             break;
  481.     }
  482.     
  483.     // did we find a pane with balloon data ?
  484.     if (!foundHelp)
  485.     {
  486.         // no pane was found
  487.         
  488.         if (removeIfNotFound)
  489.         {
  490.             // remove any currently displayed balloon
  491.             
  492.             if (::HMIsBalloon())
  493.             {
  494.                 err = ::HMRemoveBalloon();
  495.                 ThrowIfOSErr_(err);
  496.             }
  497.             
  498.             if (sLastBalloonPane != NULL)
  499.                 ClearCache();
  500.         }
  501.         
  502.         return;
  503.     }
  504.     
  505.     paneChanged        = (theHitPane  != sLastBalloonPane);
  506.     indexChanged    = (theHitIndex != sLastHelpIndex);
  507.     rectChanged        = !::EqualRect(&theHotRect, &sLastHelpRect);
  508.     dataChanged        = (paneChanged || indexChanged || rectChanged);
  509.     
  510.     if (!dataChanged && ::HMIsBalloon())
  511.     {
  512.         // the new data is still valid -- we don't need to do anything
  513.         return;
  514.     }
  515.     
  516.     if (dataChanged && ::HMIsBalloon())
  517.     {
  518.         // we have new data, but there's already a balloon displayed;  
  519.         // remove it
  520.         
  521.         err = ::HMRemoveBalloon();
  522.         ThrowIfOSErr_(err);
  523.     }
  524.     
  525.     // if we're displaying help for the same pane as the old one, place 
  526.     // the tip at the old location
  527.     if (!paneChanged && !rectChanged)
  528.     {
  529.         theTipPoint = sLastHelpTip;
  530.     }
  531.         
  532.     Rect    savedLastHelpRect;
  533.     
  534.     savedLastHelpRect    = sLastHelpRect;
  535.     sLastHelpRect        = theHotRect;
  536.     
  537.     // display the new balloon
  538.     err = ::HMShowBalloon(&helpMsg, theTipPoint, &sLastHelpRect, NULL, 
  539.                           helpProcID, helpVariant, helpOptions);
  540.     
  541.     if (err == noErr)
  542.     {
  543.         // cache the new info
  544.         sLastBalloonPane    = theHitPane;
  545.         sLastBalloonTracker    = this;
  546.         sLastHelpIndex        = theHitIndex;
  547.         sLastHelpOptions    = helpOptions;
  548.         sLastHelpProcID        = helpProcID;
  549.         sLastHelpVariant    = helpVariant;
  550.         sLastHelpTip        = theTipPoint;
  551.     }
  552.     else if ((err != hmHelpDisabled) && (err != hmBalloonAborted))
  553.     {
  554.         sLastHelpRect = savedLastHelpRect;
  555.         
  556.         ThrowOSErr_(err);
  557.     }
  558. }
  559.  
  560.  
  561. // ---------------------------------------------------------------------------
  562. //        • RemoveBalloons
  563. // ---------------------------------------------------------------------------
  564. //    Removes any currently displayed help balloon.
  565.  
  566. void
  567. LBalloonTracker::RemoveBalloons()
  568. {
  569.     OSErr    err;
  570.     
  571.     if (::HMGetBalloons() && ::HMIsBalloon())
  572.     {
  573.         // A balloon is currently visible -- remove it
  574.         
  575.         err = ::HMRemoveBalloon();
  576.         ThrowIfOSErr_(err);
  577.     }
  578.     
  579.     ClearCache();
  580. }
  581.  
  582.  
  583. // ---------------------------------------------------------------------------
  584. //        • RemoveBalloonsIfInTracker
  585. // ---------------------------------------------------------------------------
  586. //    Removes any currently displayed help balloon if the currently cached 
  587. //    balloon tracker is "this".
  588.  
  589. void
  590. LBalloonTracker::RemoveBalloonsIfInTracker()
  591. {
  592.     if (this == sLastBalloonTracker)
  593.         RemoveBalloons();
  594. }
  595.  
  596.  
  597. // ---------------------------------------------------------------------------
  598. //        • FindBalloon
  599. // ---------------------------------------------------------------------------
  600. //    Given a Pane ID and a help message index, returns the help message text 
  601. //    and other info necessary to display a help balloon.  Returns true if the 
  602. //    given pane's help info was found and valid;  else, returns false.
  603.  
  604. Boolean
  605. LBalloonTracker::FindBalloon(
  606.     PaneIDT                inPaneID, 
  607.     Int16                inHelpIndex, 
  608.     HMMessageRecord&    outHelpMsg, 
  609.     Int16&                outHelpOptions, 
  610.     Int16&                outHelpProcID, 
  611.     Int16&                outHelpVariant) const
  612. {
  613.     Loader                loadHelp(*this);
  614.     BalloonDef*            balloons;
  615.     BalloonDataOrChar*    bdoc;
  616.     Boolean                found, goodData;
  617.     
  618.     if (!HasBalloonData())
  619.         return (false);
  620.     
  621.     balloons    = *mBalloonData;
  622.     bdoc        = balloons->elem;
  623.     found        = false;
  624.     
  625.     // loop through the help resource, looking for our pane ID
  626.     for (Uint16 i = 0; i < balloons->count; i++)
  627.     {
  628.         if (bdoc->b.paneID == inPaneID)
  629.         {
  630.             found = true;
  631.             break;
  632.         }
  633.         
  634.         bdoc = (BalloonDataOrChar *) &bdoc->c[bdoc->b.length];
  635.     }
  636.     
  637.     if (!found)
  638.         return (false);
  639.     
  640.     outHelpOptions    = (balloons->options & (hmSaveBitsNoWindow | hmSaveBitsWindow)) >> 2;
  641.     outHelpProcID    = balloons->procid;
  642.     outHelpVariant    = balloons->variant;
  643.     
  644.     // fill in the help message record
  645.     switch (bdoc->b.type)
  646.     {
  647.     case kHMStringItem:
  648.         {
  649.             ConstStringPtr    pStr    = bdoc->b.u.pstrs;
  650.             
  651.             while (inHelpIndex-- > 0)
  652.                 pStr = pStr + StrLength(pStr) + 1;
  653.             
  654.             LString::CopyPStr(pStr, outHelpMsg.u.hmmString);
  655.             
  656.             outHelpMsg.hmmHelpType    = khmmString;
  657.             goodData                = (StrLength(outHelpMsg.u.hmmString) > 0);
  658.         }
  659.         break;
  660.         
  661.     case kHMPictItem:
  662.         outHelpMsg.hmmHelpType    = khmmPict;
  663.         outHelpMsg.u.hmmPict    = bdoc->b.u.picts[inHelpIndex];
  664.         goodData                = (outHelpMsg.u.hmmPict != 0);
  665.         break;
  666.         
  667.     case kHMStringResItem:
  668.         outHelpMsg.hmmHelpType    = khmmStringRes;
  669.         outHelpMsg.u.hmmStringRes = bdoc->b.u.stres[inHelpIndex];
  670.         goodData                = ((outHelpMsg.u.hmmStringRes.hmmResID != 0) && 
  671.                                    (outHelpMsg.u.hmmStringRes.hmmIndex > 0));
  672.         break;
  673.         
  674.     case kHMTEResItem:
  675.         outHelpMsg.hmmHelpType    = khmmTERes;
  676.         outHelpMsg.u.hmmTERes    = bdoc->b.u.teres[inHelpIndex];
  677.         goodData                = (outHelpMsg.u.hmmTERes != 0);
  678.         break;
  679.         
  680.     case kHMSTRResItem:
  681.         outHelpMsg.hmmHelpType    = khmmSTRRes;
  682.         outHelpMsg.u.hmmSTRRes    = bdoc->b.u.strs[inHelpIndex];
  683.         goodData                = (outHelpMsg.u.hmmSTRRes != 0);
  684.         break;
  685.         
  686.     default:
  687.         SignalPStr_("\pUndefined help data type!");
  688.         goodData = false;
  689.         break;
  690.     }
  691.     
  692.     return (found && goodData);
  693. }
  694.